package emitter

import (
	"mi/compiler/diagnostic"
	"mi/compiler/host"
	"mi/internal/xpath"
	"os"
	"path/filepath"
	"reflect"
)

func isNil(i interface{}) bool {
	ret := i == nil
	if !ret {
		vi := reflect.ValueOf(i)
		kind := reflect.ValueOf(i).Kind()
		if kind == reflect.Slice ||
			kind == reflect.Map ||
			kind == reflect.Chan ||
			kind == reflect.Interface ||
			kind == reflect.Func ||
			kind == reflect.Ptr {
			return vi.IsNil()
		}
	}

	return ret
}

func assert(expr bool) {
	if !expr {
		panic("Assert Fail")
	}
}

func makeDirAll(path string, perm os.FileMode) []*diagnostic.Diagnostic {
	var result []*diagnostic.Diagnostic
	var err = os.MkdirAll(path, os.ModePerm)
	if err != nil {
		result = append(result, diagnostic.CreateCompilerDiagnostic(
			diagnostic.M_Could_not_make_dir_0_Colon_1, path, err.Error()))
	}
	return result
}

func writeFile(host host.CompilerHost , uri xpath.URI, data []byte) []*diagnostic.Diagnostic {
	var result []*diagnostic.Diagnostic
	host.WriteFile(uri, data, func(hostErrorMessage string) {
		result = append(result, diagnostic.CreateCompilerDiagnostic(
			diagnostic.M_Could_not_write_file_0_Colon_1, uri.Filename(), hostErrorMessage))
	})
	return result
}

func removeContents(dir string) error {
	d, err := os.Open(dir)
	if err != nil {
		return err
	}
	defer d.Close()
	names, err := d.Readdirnames(-1)
	if err != nil {
		return err
	}
	for _, name := range names {
		err = os.RemoveAll(filepath.Join(dir, name))
		if err != nil {
			return err
		}
	}
	return nil
}

func cleanFolder(dir string) *diagnostic.Diagnostic {
	// Make sure the output folder exists and is clean
	_, err := os.Stat(dir)
	if err != nil {
		// The folder does not exist, we create one
		if os.IsNotExist(err) {
			err = os.MkdirAll(dir, os.ModePerm)
			if err != nil {
				return diagnostic.CreateCompilerDiagnostic(
					diagnostic.M_Failed_to_create_folder_0_colon_1, dir, err.Error())
			}
		} else {
			return diagnostic.CreateCompilerDiagnostic(
				diagnostic.M_Failed_to_obtain_file_0_information_colon_1, dir, err.Error())
		}
	} else {
		// Clear the contents of output folder
		err = removeContents(dir)
		if err != nil {
			return diagnostic.CreateCompilerDiagnostic(
				diagnostic.M_0_error_Colon_1, "removeContents", err.Error())
		}
	}

	return nil
}